package com.carter.springframework.beans.factory.support;

import com.carter.springframework.beans.factory.FactoryBean;
import com.carter.springframework.beans.factory.config.BeanDefinition;
import com.carter.springframework.beans.factory.config.BeanPostProcessor;
import com.carter.springframework.beans.factory.config.ConfigurableBeanFactory;
import com.carter.springframework.beans.exception.BeanException;
import com.carter.springframework.util.ClassUtils;
import com.carter.springframework.util.StringValueResolver;

import java.util.ArrayList;
import java.util.List;

//抽象类
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport  implements ConfigurableBeanFactory {

    private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

    private List<StringValueResolver> embeddedValueResolvers = new ArrayList<>();
    @Override
    public Object getBean(String beanName,Object... args) throws BeanException{
        //这里先尝试获取单例Bean，如果可以获取得到就先返回
        Object bean = getSingleton(beanName);
        if (bean!=null){
            //return getObjectFromFactoryBean(bean,beanName);
            return getObjectFromFactoryBean((FactoryBean<?>) bean,beanName);
        }
        //如果上面获取bean失败，就需要先调用抽象的获取bean定义的方法，拿到bean的定义,然后再通过这个来新创建一个Bean
        BeanDefinition beanDefinition = getBeanDefinition(beanName);
        bean = createBean(beanName, beanDefinition, args);
        return getObjectForBeanInstance(bean,beanName);
    }

    /**
     * 对factoryBean类型的bean进行处理
     * @param beanInstance
     * @param beanName
     * @return
     */
    private Object getObjectForBeanInstance(Object beanInstance, String beanName) {
        if (beanInstance instanceof FactoryBean){
            return getObjectFromFactoryBean(((FactoryBean<?>) beanInstance), beanName);
        }
        return beanInstance;
    }

    //抽象方法，获取bean的定义
    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeanException;

    //抽象方法，创建Bean
    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition,Object[] args) throws BeanException;


    @Override
    public void addBeanPostProcessor(BeanPostProcessor processor) {
        this.beanPostProcessors.remove(processor);
        this.beanPostProcessors.add(processor);
    }

    public List<BeanPostProcessor> getBeanPostProcessors() {
        return beanPostProcessors;
    }

    @Override
    public <T> T getBean(String beanName,Class<T> requiredType) throws BeanException{
        Object bean = getBean(beanName);
        return requiredType.cast(bean);
    }

    private ClassLoader classLoader = ClassUtils.getDefaultClassLoader();

    public ClassLoader getClassLoader(){
        return this.classLoader;
    }

    @Override
    public void addEmbeddedValueResolver(StringValueResolver resolver) {
        this.embeddedValueResolvers.add(resolver);
    }

    @Override
    public String resolveEmbeddedValue(String value) {
        String result  = value;
        for (StringValueResolver resolver : embeddedValueResolvers) {
            result = resolver.resolveStringValue(value);
        }
        return result;
    }
}
